/*
 * @(#) BaseService.java 2013-3-29 上午11:33:02
 * Copyright 2013 Rockwell Automation, Inc. All rights reserved.
 * Rockwell Automation PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */package com.osi.mes.base;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;

import jxl.Workbook;
import jxl.format.Alignment;
import jxl.format.VerticalAlignment;
import jxl.write.Label;
import jxl.write.NumberFormats;
import jxl.write.WritableCellFormat;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import pnuts.lang.Context;

import com.datasweep.compatibility.client.ATColumnDefinition;
import com.datasweep.compatibility.client.ATDefinition;
import com.datasweep.compatibility.client.ATHandler;
import com.datasweep.compatibility.client.ATRow;
import com.datasweep.compatibility.client.ATRowFilter;
import com.datasweep.compatibility.client.DatasweepException;
import com.datasweep.compatibility.client.Part;
import com.datasweep.compatibility.client.PartFilter;
import com.datasweep.compatibility.client.Report;
import com.datasweep.compatibility.client.Response;
import com.datasweep.compatibility.client.UserSequence;
import com.datasweep.compatibility.client.UserSequenceFilter;
import com.datasweep.compatibility.client.UserSequenceValue;
import com.datasweep.compatibility.pnuts.Functions;
import com.datasweep.compatibility.ui.Time;
import com.datasweep.plantops.common.constants.filtering.IBOMFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.IFilterComparisonOperators;
import com.datasweep.plantops.common.constants.filtering.IPartFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.IUserSequenceFilterAttributes;
import com.osi.mes.base.object.UIData;
import com.osi.mes.base.object.UIPart;
import com.osi.mes.base.util.DataUtility;
import com.osi.mes.constants.IATConstants;
import com.osi.mes.constants.IDateFormatConstants;
import com.osi.mes.constants.IExcelConstants;
import com.osi.mes.constants.IModuleConstants;
import com.osi.mes.constants.IUDADefinitions;
import com.osi.mes.excel.BaseRowObject;
import com.osi.mes.excel.ExcelPoiParser;
import com.osi.mes.pm.constants.IWebServiceConstants;
import com.osi.mes.qm.base.constants.IATNames;
import com.osi.mes.utils.FunctionUtils;
import com.osi.mes.utils.ReponseUtils;
import com.osi.mes.utils.StringUtils;
import com.rockwell.ftpc.framework.common.DateTimeUtils;
import com.rockwell.operationalreporting.ReportInfo;


public class BaseService implements IATConstants, IUDADefinitions, IATNames, IModuleConstants,IExcelConstants,IWebServiceConstants{
	
	private static final String PM_MESSAGE = "OSIPMMessage";
	protected boolean isDebug = false;
	private Functions functions;

	public BaseService(Context context) {
		this(FunctionUtils.getFunction(context));
	}

	public BaseService(Functions functions) {
		this.functions = functions;
	}

	protected Functions getFunctions() {
		return this.functions;
	}

	
	//Module base start
	/**
	 * 构建XML数据时添加数据�?用方�?
	 */
	protected static ArrayList<Object> toTransferValue(Object obj) {
		ArrayList<Object> data = new ArrayList<Object>();
		data.add(obj);
		return data;
	}
	
	/**
	 * 取得数据时使用的通用方法
	 */
	protected static String getTransferValue(Hashtable<String, ArrayList<Object>> data,String keyName){
		ArrayList<Object> arrayData = data.get(keyName);
		if(arrayData != null){
			return (String)arrayData.get(0);
		}
		return null;
	}
	
	 /**
     * 将UDA字段转为Int型
     */
    protected Integer toInteger(Object udaData) throws Exception{
    	return DataUtility.toInteger(udaData);
    }
    
	 /**
     * 将UDA字段转为Float型
     */
    protected Float toFloat(Object udaData) throws Exception{
    	return DataUtility.toFloat(udaData);
    }
    
    /**
     * 将UDA转换为布尔值
     */
    protected Boolean toBoolean(Object udaData) throws Exception{
    	return DataUtility.toBoolean(udaData);
    }
	
	/**
	 * 抛出异常
	 */
	protected void throwException(String message) throws Exception
	{
//		throw new Exception(message);
		throw new Exception(getMessage(message));
	}
	
	protected String getMessage(String messageId)
	{
		return getFunctions().getMessage(PM_MESSAGE, messageId);
	}
	
	/**
	 * 检查Response
	 */
	protected void checkResponse(Response response) throws Exception
	{
		if(response.isError())
		{
			throwException(response.getFirstErrorMessage());
		}
	}
	
	/**
	 * 获取数据库当前时间
	 * @author Nemo
	 */
	protected Time getTrxTime(){
		return getFunctions().getDBTime();
	}
	
	/**
	 * 获得当天开始时间
	 * @author Nemo
	 */
	public Time getDayStart(){
		return getDayStart(getTrxTime());
	}
	
	public Time getDayStart(Time currentTime){
		return DateTimeUtils.getDayStart(currentTime);
	}
	
	/**
	 * 获得当天结束时间
	 * @author Nemo
	 */
	public Time getDayEnd(Time currentTime){
		return DateTimeUtils.getDayEnd(currentTime);
	}
	
	public Time getDayEnd(){
		return getDayEnd(getTrxTime());
	}
	
	/**
	 * 获得当前的时间
	 */
	
	/**
	 * 判断AT表中某列数据是否存在
	 */
	protected boolean isATDataExist(String tableName, String columnName,
			Object value) throws Exception {
		if (StringUtils.isNull(tableName)) {
			throw new Exception("表名不允许为空");
		}

		if (StringUtils.isNull(columnName)) {
			throw new Exception("字段名不允许为空");
		}

		if (value == null) {
			throw new Exception("数据不允许为空");
		}

		ATRowFilter atRowFilter = getFunctions().createATRowFilter(tableName);
		atRowFilter.forColumnNameEqualTo(columnName, value);
		return getFunctions().getFilteredATRowCount(atRowFilter) > 0;
	}
	
	/**
	 * 查询所有产品
	 * @author Nemo
	 */
	public Vector<UIPart> getAllProducts() 
	{
		Vector<UIPart> uiParts = new Vector<UIPart>();
		PartFilter partFilter = getFunctions().createPartFilter();
		partFilter.addSearchBy(IPartFilterAttributes.NUMBER, IFilterComparisonOperators.IN, IBOMFilterAttributes.BOM_NAME,getFunctions().createBomFilter());
		Vector<Part> parts = getFunctions().getFilteredParts(partFilter);
		for (int i = 0; i < parts.size(); i++)
		{
			uiParts.add(new UIPart(parts.get(i)));
		}
		return uiParts;
	}
	
	/**
	 * 获得所有产线
	 * @author Nemo
	 */
	public Vector<UIData> getAllProductionLines()
	{
		return getFunctions().getAllProductionLines();
	}
	
	// 删除ATRow
	public boolean deleteATRow(ATRow atRow)
	{
		boolean isSucc = true;
		   Response response = atRow.delete(getTrxTime(), null, null);
		   if(response.isError())
			   isSucc = false;
		return isSucc;
	}
	
	// 修改ATRow
	public boolean mdATRow(ATRow atRow) throws DatasweepException
	{
		boolean isSucc = true;
			Response response =  atRow.save(getTrxTime(), null, null);
			if(response.isError())
				isSucc = false;
		
		return isSucc;
	}
	
	public boolean mdATRow(ATRow atRow,Hashtable values) throws Exception
	{
		boolean isSucc = true;
		for (Iterator itr = values.keySet().iterator(); itr.hasNext();) {
			String key = (String) itr.next();
			Object value = values.get(key);
			atRow.setValue(key, value);
		}

		Response response = atRow.save(getTrxTime(), null, null);
		if (response.isError())
			isSucc = false;

		return isSucc;
	}
	
	// 添加ATRow
	public boolean addATRow(String atDefName,Hashtable values) throws Exception
	{
		boolean isSucc = true;
		ATHandler atHandler = getFunctions().createATHandler(atDefName);
		ATRow atRow = atHandler.createATRow();

		for (Iterator itr = values.keySet().iterator(); itr.hasNext();) {
				String key = (String) itr.next();
				Object value = values.get(key);
				atRow.setValue(key, value);
		}

		Response response = atHandler.save(getTrxTime(), null, null);
		if (response.isError())
			isSucc = false;
		return isSucc;
	}
	
	// 查询ATRows
	public Vector getATRowData(String atDefName,Hashtable conditions) throws DatasweepException
	{
		Vector atRows = new Vector();
		ATHandler atHandler = getFunctions().createATHandler(atDefName);
		ATRowFilter rowFilter = getFunctions().createATRowFilter(atDefName);
		int count = conditions.size();

		for (Iterator itr = conditions.keySet().iterator(); itr.hasNext();) {
			String key = (String) itr.next();
			Object value = conditions.get(key);
			if(value instanceof String)
			{
				rowFilter.forColumnNameContaining(key, value.toString());
			}
			else if(value instanceof Object[])
			{
				Object[] timeFromTo = (Object[])value;
				Time start = (Time)timeFromTo[0];
				Time to = (Time)timeFromTo[1];
				if (start != null)
				{
					start = getDayStart(start);
					rowFilter.forColumnNameGreaterThanOrEqualTo(
						key, start);
				}
				if (to != null)
				{
					to = getDayEnd(to);
					rowFilter.forColumnNameLessThan(
						key, to);
				}
			}
			else
			{
				rowFilter.forColumnNameEqualTo(key, value);
			}
		}
		atRows = atHandler.getATRowsByFilter(rowFilter, false);
		return atRows;
	}
	
	// import excel to atRow
	public int importExcelDataToAtRows(String atDefName,String excelFilePath,String excelRowClass,int ingnoreTopRows,int ingnoreBottomRowNumber,String dateFormatter) throws Exception
	{
		int referenceRows = 0;
		ExcelPoiParser.ingnoreTopRowNumber = ingnoreTopRows;
		ExcelPoiParser.ingnoreBottomRowNumber = ingnoreBottomRowNumber;
		ExcelPoiParser.DATE_FORMAT1 = dateFormatter;
		
		List res = ExcelPoiParser.parseExcelFile(excelFilePath, excelRowClass);
		System.out.println("res: "+res.size());
		if(res == null || res.size() == 0)
			return referenceRows;
		
		Class rowObjectClass = Class.forName(excelRowClass);
		BaseRowObject rowObject = (BaseRowObject) rowObjectClass.newInstance();
		int propertiesCount = rowObject.getPropertyCount();
		
		ATHandler atHandler = getFunctions().createATHandler(atDefName);
		for(int i=0;i<res.size();i++)
		{
			Object obj = res.get(i);
			if(obj.getClass().toString().equals(excelRowClass))
			{
				ATRow atRow = atHandler.createATRow();
				for(int j=0;j<propertiesCount;j++)
				{
					String fieldName = rowObject.getPropertyName(j);
					Object cellVal = getPropertyValue(obj,fieldName);
					Class atColumnClass = getATColumnClass(atRow,fieldName);
					if(cellVal.getClass().toString().equals(atColumnClass.toString()))
						atRow.setValue(fieldName, cellVal);
					else if(cellVal instanceof String)
					{
						if(atColumnClass.equals("class java.lang.Float"))
						{
							atRow.setValue(fieldName, new Float(cellVal.toString()));
						}
						else if(atColumnClass.equals("class java.lang.Long"))
						{
							atRow.setValue(fieldName, new Long(cellVal.toString()));
						}
					}	
				}
				if(mdATRow(atRow))
					referenceRows ++;
			}
		}
		
		return referenceRows;
	}
	
	private  Object getPropertyValue(Object bean, String propertyName)
			throws IllegalArgumentException, IllegalAccessException,
			InvocationTargetException, SecurityException, NoSuchMethodException {
		StringBuffer sb = new StringBuffer();
		char[] ch = propertyName.toCharArray();
		sb.append(Character.toTitleCase(ch[0]));

		for (int y = 1; y < ch.length; y++) {
			sb.append(ch[y]);
		}

		String proName = "get" + sb.toString();
		Class clazz = bean.getClass();
		Method method = clazz.getMethod(proName);
		method.setAccessible(true);
		return method.invoke(bean);
	}
	
	private  Class getATColumnClass(ATRow atRow,String column)
	{
		ATDefinition atDef = atRow.getATDefinition();
		if(atDef == null)
			return null;
		
		ATColumnDefinition atColDef =  atDef.getATColumnDefinition(column);
		return atColDef.getClass();
	}
	
	public ATRow getAtRowByKey(Long key,String atDefName) throws DatasweepException
	{
		ATHandler atHandler = getFunctions().createATHandler(atDefName);
		ATRowFilter rowFilter = getFunctions().createATRowFilter(atDefName);
		rowFilter.forATRowKeyEqualTo(key);
		Vector matchedEqus = atHandler.getATRowsByFilter(rowFilter, false);
		
		if(matchedEqus == null || matchedEqus.size() == 0)
			return null;
		
		return (ATRow)matchedEqus.get(0);
	}
	
	@SuppressWarnings("unchecked")
	public Vector<ATRow> getATRows(ATRowFilter atRowFilter)
	{
		return getFunctions().getFilteredATRows(atRowFilter, false);
	}
	
	public Response saveATRow(ATRow atRow)
	{
		Response response = atRow.save(getFunctions().getDBTime(), null, null);
		return response;
	}
	
	public Response deleteAtRow(ATRow atRow)
	{
		return atRow.delete(getFunctions().getDBTime(), null, null);
	}
	
	//创建一个ATROW
	public ATRow createATRow(String atDefName)
	{
		ATHandler atHandler = getFunctions().createATHandler(atDefName);
		return  atHandler.createATRow();
	}
	
	/**
	 * 创建错误类型的Response
	 * @param e 异常
	 * @return 包含了error的Response
	 */
	public Response createErrorResponse(Throwable e){
		Functions fc = this.getFunctions();
		return ReponseUtils.createErrorResponse(fc, e);
	}
	
	/**
	 * 判断该文件是否存在，若存在，则将该文件重命名
	 * @throws IOException 
	 */
	private static void backupFile(File excelFile) throws IOException {
		if (excelFile.exists()) {
			String fileBakDir = excelFile.getAbsolutePath() + ".bak";
			File excelBakFile = new File(fileBakDir);
			if (excelBakFile.exists()) {
				excelBakFile.delete();
			}
			excelFile.renameTo(excelBakFile);
		}
		
		excelFile.createNewFile();
	}
	
	protected void toExcel(String fileDir, String[][] data,String sheetName) throws Exception
	{
		// 判断该文件是否存在，若存在，则将该文件重命名
		File excelFile = new File(fileDir);
		backupFile(excelFile);

		WritableWorkbook workBook = Workbook.createWorkbook(excelFile);
		WritableSheet sheet = workBook.createSheet(
			sheetName, 0);

		for (int i = 0; i < data.length; i++)
		{
			String[] rowData_ = data[i];
			for (int j = 0; j < rowData_.length; j++)
			{
				if (i == 0)
				{
					WritableCellFormat wcfTitle = new WritableCellFormat(NumberFormats.TEXT);
					wcfTitle.setAlignment(Alignment.CENTRE);
					Label label = new Label(j, i, data[i][j], wcfTitle);
					sheet.addCell(label);
					sheet.mergeCells(
						0, 0, rowData_.length, 0);
					break;
				}
				// 若第二行中单元格和前一个单元格一样（同一产线），则合并单元格
				else if (i == 1)
				{
					if(j == 0)
					{
						WritableCellFormat wcfBold = new WritableCellFormat(NumberFormats.TEXT);
						wcfBold.setBorder(
							jxl.format.Border.ALL, jxl.format.BorderLineStyle.THICK);
						wcfBold.setAlignment(Alignment.CENTRE);
						Label label = new Label(j, i, data[i][j], wcfBold);
						sheet.addCell(label);
					}
					// merge产线
					else if (j > 1 && data[i][j].equals(data[i][j - 1]))
					{
						sheet.mergeCells(
							j - 1, i, j, i);
					}
					else
					{
						WritableCellFormat wcfBold = new WritableCellFormat(NumberFormats.TEXT);
						wcfBold.setBorder(
							jxl.format.Border.TOP, jxl.format.BorderLineStyle.THICK);
						wcfBold.setBorder(
							jxl.format.Border.BOTTOM, jxl.format.BorderLineStyle.THICK);
						if(j == rowData_.length-1)
						{
							wcfBold.setBorder(
								jxl.format.Border.RIGHT, jxl.format.BorderLineStyle.THICK);
						}
						wcfBold.setAlignment(Alignment.CENTRE);
						Label label = new Label(j, i, data[i][j], wcfBold);
						sheet.addCell(label);
					}
				}
				// 其余单元格
				else
				{
					Label label = null;
					if (j == 0)
					{
						WritableCellFormat wcfBold = new WritableCellFormat(NumberFormats.TEXT);
						wcfBold.setBorder(
							jxl.format.Border.LEFT, jxl.format.BorderLineStyle.THICK);
						wcfBold.setBorder(
							jxl.format.Border.RIGHT, jxl.format.BorderLineStyle.THICK);
						wcfBold.setAlignment(Alignment.RIGHT);
						wcfBold.setVerticalAlignment(VerticalAlignment.CENTRE);
						label = new Label(j, i, data[i][j], wcfBold);
					}
					else
					{
						WritableCellFormat wcfBold = new WritableCellFormat(NumberFormats.TEXT);
						wcfBold.setBorder(
							jxl.format.Border.ALL, jxl.format.BorderLineStyle.DASHED);
						wcfBold.setAlignment(Alignment.CENTRE);
						wcfBold.setVerticalAlignment(VerticalAlignment.CENTRE);
						label = new Label(j, i, data[i][j], wcfBold);
					}
					sheet.addCell(label);

					if(i%2==0)
					{
						sheet.setRowView(
							i, 1000);
						sheet.setColumnView(
							j, 15);
					}
				}
			}
		}

		workBook.write();
		workBook.close();
	}
	
	public String getSerialNum()
	{
		Time t = getFunctions().createTime();
		int random = new Random().nextInt(100);
		return t.toLong()+""+random;
	}
	
    /**
     * 获取流水号
     * @param sequenceName 序列名称
     * @return 流水号
     * @throws Exception
     */
    protected int getSequenceNumber(String sequenceName)throws Exception{
        //清除无用序列
        removeOverdueUserSequence();
        //获取或生成序列
        UserSequence userSequence = getFunctions().getUserSequenceByName(sequenceName);
        if (userSequence == null) {
            userSequence = getFunctions().createUserSequence(sequenceName);
            userSequence.setInitialValue(0);
            userSequence.setIncrementValue(1);
            userSequence.setMaxValue(99);
            //设置删除标记
            String dateString = DateTimeUtils.formatDate(getTrxTime(),  IDateFormatConstants.DATE_TIME_FORMAT_DAY);
            userSequence.setDescription(dateString);
            Response response = userSequence.save();
            if (response.isError()) {
                throw new Exception("创建流水号序列出错");
            } else {
                userSequence = getFunctions().getUserSequenceByName(sequenceName);
            }
        }
        Response response = userSequence.getNextValue();
        if (response.isError()) {
            throw new Exception("无法取得下一个流水号");
        }
        UserSequenceValue userSequenceValue = (UserSequenceValue) response.getResult();
        return userSequenceValue.getValue();
    }


    /**
     * 删除非当天的序列组
     * @author Nemo
     */
    private void removeOverdueUserSequence() {
        String dateString = DateTimeUtils.formatDate(getTrxTime(),  IDateFormatConstants.DATE_TIME_FORMAT_DAY);
        UserSequenceFilter userSequenceFilter = getFunctions().createUserSequenceFilter();
        userSequenceFilter.addSearchBy(IUserSequenceFilterAttributes.DESCRIPTION, IFilterComparisonOperators.NOT_EQUAL_TO, dateString);
        Vector userSequences = getFunctions().getFilteredUserSequences(userSequenceFilter);
        for (int i = 0; i < userSequences.size(); i++) {
            UserSequence userSequence = (UserSequence) userSequences.get(i);
            String description = userSequence.getDescription();
            Time day = DateTimeUtils.parseDateOfPnut(description,  IDateFormatConstants.DATE_TIME_FORMAT_DAY);
            if (getDayStart().compareTo(day) == 1) {
                Long userSequenceKey = userSequence.getKey();
                getFunctions().removeUserSequenceByKey(userSequenceKey);
            }
        }
    }
    
    /**
	 * 格式化条码
	 */
	protected String format(String source, int length, String prefix)
			throws Exception {
		if (source.length() > length) {
			throw new Exception("The length of serial number '" + source
					+ "' is more than the lenght '" + length + "' user defined");
		}
		StringBuffer sb = new StringBuffer();
		if (length > 0) {
			for (int i = 0; i < length; i++) {
				sb.append(prefix);
			}
		}
		return sb.substring(0, length - source.length()) + source;
	}
	
	/**
	 * 导出为Excel
	 */
	public boolean exportToExcel(String filePath,Report report)
	{
		boolean isSucc = true;
		File sourceFile = new File(filePath);
		JRXlsExporter exporter = new JRXlsExporter();
		
		ReportInfo rptInfo = report.getReportInfo();
		JasperPrint jaspPrint = (JasperPrint)rptInfo.getInternalRepresentation();
		exporter.setParameter(JRExporterParameter.JASPER_PRINT, jaspPrint);
		exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,
				sourceFile.toString());
		exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,
				Boolean.FALSE);

		try {
			exporter.exportReport();
		} catch (JRException e) {
			e.printStackTrace();
			isSucc = false;
		}
		
		return isSucc;
	}

}
